package log

import (
	"context"
	"os"

	"gitee.com/zacyuan/yuan/pkg/config"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

const (
	GinKey    = "gin_log"
	RequestID = "request_id"
)

type Logger = zap.SugaredLogger
type SugaredLogger = zap.SugaredLogger

var (
	log, _ = zap.NewDevelopment()
	sugar  = log.Sugar()
)

var (
	DPanic      = sugar.DPanic
	DPanicf     = sugar.DPanicf
	DPanicln    = sugar.DPanicln
	DPanicw     = sugar.DPanicw
	Debug       = sugar.Debug
	Debugf      = sugar.Debugf
	Debugln     = sugar.Debugln
	Debugw      = sugar.Debugw
	Desugar     = sugar.Desugar
	Error       = sugar.Error
	Errorf      = sugar.Errorf
	Errorln     = sugar.Errorln
	Errorw      = sugar.Errorw
	Fatal       = sugar.Fatal
	Fatalf      = sugar.Fatalf
	Fatalln     = sugar.Fatalln
	Fatalw      = sugar.Fatalw
	Info        = sugar.Info
	Infof       = sugar.Infof
	Infoln      = sugar.Infoln
	Infow       = sugar.Infow
	Level       = sugar.Level
	Named       = sugar.Named
	Panic       = sugar.Panic
	Panicf      = sugar.Panicf
	Panicln     = sugar.Panicln
	Panicw      = sugar.Panicw
	Sync        = sugar.Sync
	Warn        = sugar.Warn
	Warnf       = sugar.Warnf
	Warnw       = sugar.Warnw
	With        = sugar.With
	WithOptions = sugar.WithOptions

	String = zap.String
)

func Start() error {
	_ = config.UnmarshalKey("log", &defaultOptions)

	var coreArr []zapcore.Core
	//获取编码器
	encoderConfig := zap.NewProductionEncoderConfig()            //NewJSONEncoder()输出json格式，NewConsoleEncoder()输出普通文本格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder        //指定时间格式
	encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder //按级别显示不同颜色，不需要的话取值zapcore.CapitalLevelEncoder就可以了
	//encoderConfig.EncodeCaller = zapcore.FullCallerEncoder        //显示完整文件路径
	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	//日志级别
	highPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //error级别
		return lev >= zap.ErrorLevel
	})
	lowPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool { //info和debug级别,debug级别是最低的
		return lev < zap.ErrorLevel && lev >= zap.DebugLevel
	})

	//info文件writeSyncer
	infoFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   defaultOptions.Filename + "_info.log", //日志文件
		MaxSize:    defaultOptions.MaxSize,                //文件大小限制,单位MB
		MaxBackups: defaultOptions.MaxBackups,             //最大保留日志文件数量
		MaxAge:     defaultOptions.MaxAge,                 //日志文件保留天数
		Compress:   defaultOptions.Compress,               //是否压缩处理
	})
	infoFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(infoFileWriteSyncer, zapcore.AddSync(os.Stdout)), lowPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志
	//error文件writeSyncer
	errorFileWriteSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   defaultOptions.Filename + "_error.log", //日志文件
		MaxSize:    defaultOptions.MaxSize,                 //文件大小限制,单位MB
		MaxBackups: defaultOptions.MaxBackups,              //最大保留日志文件数量
		MaxAge:     defaultOptions.MaxAge,                  //日志文件保留天数
		Compress:   defaultOptions.Compress,                //是否压缩处理
	})
	errorFileCore := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(errorFileWriteSyncer, zapcore.AddSync(os.Stdout)), highPriority) //第三个及之后的参数为写入文件的日志级别,ErrorLevel模式只记录error级别的日志

	coreArr = append(coreArr, infoFileCore)
	coreArr = append(coreArr, errorFileCore)
	log = zap.New(zapcore.NewTee(coreArr...), zap.AddCaller()) //zap.AddCaller()为显示文件名和行号，可省略
	sugar = log.Sugar()

	DPanic = sugar.DPanic
	DPanicf = sugar.DPanicf
	DPanicln = sugar.DPanicln
	DPanicw = sugar.DPanicw
	Debug = sugar.Debug
	Debugf = sugar.Debugf
	Debugln = sugar.Debugln
	Debugw = sugar.Debugw
	Desugar = sugar.Desugar
	Error = sugar.Error
	Errorf = sugar.Errorf
	Errorln = sugar.Errorln
	Errorw = sugar.Errorw
	Fatal = sugar.Fatal
	Fatalf = sugar.Fatalf
	Fatalln = sugar.Fatalln
	Fatalw = sugar.Fatalw
	Info = sugar.Info
	Infof = sugar.Infof
	Infoln = sugar.Infoln
	Infow = sugar.Infow
	Level = sugar.Level
	Named = sugar.Named
	Panic = sugar.Panic
	Panicf = sugar.Panicf
	Panicln = sugar.Panicln
	Panicw = sugar.Panicw
	Sync = sugar.Sync
	Warn = sugar.Warn
	Warnf = sugar.Warnf
	Warnw = sugar.Warnw
	With = sugar.With
	WithOptions = sugar.WithOptions

	return nil
}

func WithRequestID(id string) *zap.SugaredLogger {
	return sugar.With(String(RequestID, id))
}

func GetLogger() *SugaredLogger {
	return sugar
}

func FormContext(ctx context.Context) *SugaredLogger {
	logger := sugar
	if ctx != nil {
		if l := ctx.Value(GinKey); l != nil {
			if logger, ok := l.(*SugaredLogger); ok {
				return logger
			}
		}

		if id := ctx.Value(RequestID); id != nil {
			return WithRequestID(id.(string))
		}
	}
	return logger
}
